home *** CD-ROM | disk | FTP | other *** search
- /* MIDInterface 1.11
- Copyright (C) 1985, 1986 By:
- Jay Kubicky
- 934 N. Orange St.
- Media, PA 19063
- 215-565-7761
-
- This is a VERY recent version of this program.
- It has not been 'tested' extensively, though all testing that
- has been done shows favorable results.
- All users are free, of course, to test (and debug) this software as
- desired.
-
- This program was developed under the DeSmet C compiler, and utilizes
- DeSmet's vastly useful in-line assembly language capability.
- Compiling it on other compilers (such as Lattice) may require
- EXTENSIVE modification.
-
- 2/14/86
- */
-
- #define MIDID 0xffa0
- #define MIDIS 0xffa2
- #define PIC0 0x20
- #define PIC1 0x21
- #define CSTAT 0xFFA7
- #define COUNTER1 0xFFA4
- #define COUNTER2 0xFFA5
- #define Tsize 25600 /* track size in bytes (24K) */
- #define Tk 25 /* track size in K */
- #define seg_per_trk 1600 /* track size in paragraphs */
- /* the following structures hold data for each buffer */
-
- char prog_id[]={"MIDInterface 1.11 (c) 1985, 1986 Jay Kubicky"};
-
- struct rec { /* 63 bytes long 63*16=1008 bytes total */
- char chan;
- unsigned ssize;
- char name[40];
- char transpose; /* transpose amount */
- char extra[19]; /* for later use */
- } parts[16];
-
- char in_filt; /* This is the MIDI input filter mask:
- bit: message filtered out:
- --- --------------------
- 0 Note ON
- 1 Note OFF
- 2 Program Change
- 3 Channel Pres. (After-touch)
- 4 Pitch Wheel
- 5 Control Change
- 6 Poly. Key pres. (After-touch)
- */
- char on[4]="ON "; /* 'ON' */
- char off[4]="OFF"; /* 'OFF' */
- char yes[4]="YES";
- char no[4]="NO ";
- char sin_line[80]; /* A 79 char. single line */
- unsigned r_segment;
- char *ptr, *end;
- int fd; char filename[30];
-
- int r_tempo; /* tempo val (bpm) */
- unsigned tempo; /* real tempo val. */
- char destbyte, stop;
- char clsb, cmsb, dsync, MIDIsync, audmet;
- char rbuff; /* receive buffer */
- char beat, mbeat,abeat, s_t_b, m_t_b, a_t_b; /* beats & time bases */
-
- char buffon[16]; /* true means given buff is active */
- unsigned pointers[16]; /* an array of pointers into present buffers */
- unsigned startp[16]; /* an array of starts of present buffer */
- unsigned endp[16]; /* pointers to end of songs */
- unsigned segment[16]; /* array of segments of tracks */
-
- int pfd; /* fd for printer */
- char printer; /* printer enable */
-
- extern unsigned _rax, _rbx, _rdx, _res, _rds;
-
- char LAST_STAT;
- char C_O_F;
- char clk_type; /* 0=internal, 1=external */
- char counter_dec;
- char vir_buff[1024];
- char buff1[Tsize]; /* track 0 - 3070 notes */
- char buff2[Tsize]; /* track 1 - 3070 notes */
- /* first two tracks eat up 50K */
- /* last fourteen will take 350K combined */
- /* total note storage=
- 3200 notes per track
- 51200 notes in all!!! */
-
- char *_showsp(),*_showss(),*_showds();
- main()
- {
- unsigned a;
- char clkval,sel,b; int c;
- unsigned base_seg, cont_mem;
-
- /* the following code stores the DS at 0x4FA */
- /* THIS IS VERY IMPORTANT!!!!!!!! */
- /* this allows the DS to be transffered to the RXINT function */
- # asm
- MOV CX,DS ; store DS in CX
- PUSH DS ; save DS
- MOV AX,0 ; this will be new value for DS
- MOV DS,AX ; put 0 in DS
- MOV WORD [04FAH], CX ; store DS
- POP DS ; retrieve DS
- #
-
- /* MIDInterface 1.11 16-track digital sequencer
-
- Data storage format:
- --------------------
-
- (MIDI ORIENTED COMMANDS)
- byte num: first second third fourth fifth
- +--------+----------+----------+----------+--------+
- Note ON 00vvvvvv | LLLLLLLL | MMMMMMMM | 1nnnnnnn | --
- | | | |
- Note OFF 00vvvvvv | LLLLLLLL | MMMMMMMM | 0nnnnnnn | --
- | | | |
- Prog Chan 01000000 | LLLLLLLL | MMMMMMMM | 0ppppppp | --
- | | | |
- Chan Pres 01000001 | LLLLLLLL | MMMMMMMM | 0aaaaaaa | --
- (after-touch) | | | |
- Pitch Wheel 10wwwwww | LLLLLLLL | MMMMMMMM | -- | --
- | | | |
- Cntrl Chan 11000000 | LLLLLLLL | MMMMMMMM | 0nnnnnnn | 0ccccccc
- | | | |
- Key Pres. 011vvvvv | LLLLLLLL | MMMMMMMM | 0nnnnnnn | --
- (after-touch)
-
- (INTERNAL ORIENTED COMMANDS)
- +--------+----------+----------+----------+--------+
- Change Tempo 11000001 | LLLLLLLL | MMMMMMMM | tttttttt | --
-
- End 11111111 | -- | -- | -- | --
-
-
- -------------------------------------------------------------------------
- vvvvvv - top 6 bits of velocity (NOTE ON or OFF)
- LLLLLLLL - LSB of clk
- MMMMMMMM - MSB of clk
- nnnnnnn - note for either NOTE ON or NOTE OFF
- ppppppp - new program
- aaaaaaa - chan pressure (after-touch)
- wwwwww - top six of bender
- nnnnnnn - control number
- ccccccc - control value
-
- tttttttt - new tempo value (40-200)
- */
- c=0;
- while(c<79)
- sin_line[c++]='─';
- sin_line[c]='\0';
-
- in_filt=0xff; /* Don't filter out anything */
- clk_type=0; /* internal */
- counter_dec=2;
- rbuff=255;
- segment[0]=segment[1]=_showds(); /* 1st two buffs in DS */
- startp[0]=buff1; endp[0]=buff1+Tsize-8;
- startp[1]=buff2; endp[1]=buff2+Tsize-8;
- parts[0].ssize=0; parts[1].ssize=0;
-
- /* This is the memory allocation section.
- This is really a sort of pseudo-allocation scheme
- allowing the use of the entire system memory (up to 640K).
- Memory is allocated in blocks of 25k (1600 paragraphs).
- All tracks are allocated sequentially until you run out
- of system RAM. The first two tracks are taken care of
- in the C memory, so there should always be room for these.
- */
-
- base_seg=_showss()+1; /* start just after stack */
- base_seg += (_showsp()/16); /* This is the segment boundary of
- the bottom of un-initialized mem */
- ++base_seg; /* one for a safety */
-
- cont_mem=get_av_mem();
- cont_mem *= 64; /* Find total # of system para. */
-
- /* Here's where we "allocate our memory" */
-
- _setmem(segment+4,28,0);
- c=2;
- for (a=base_seg; a < cont_mem && c < 16; a+=seg_per_trk) {
- segment[c]=a;
- startp[c]=0;
- endp[c]=Tsize-8;
- parts[c].ssize=0;
- parts[c].transpose=0;
- ++c;
- }
- m_t_b=2; s_t_b=1; a_t_b=48; /* default time bases */
- printer=0;
- scr_cla();
- printf("Do you wish to use the printer as an audio meternome?");
- if(toupper(getchar())=='Y') {
- printf("\nReady the printer and hit any key");
- getchar();
- if((pfd=open("PRN",2))==-1) {
- printf("Error opening printer ... aborting\n");
- getchar();
- exit(1);
- }
- beepp();
- printer=1;
- }
- start:
- setdart();
- intoff(); /* turn interrupts off */
- scr_cla();
- printf(" ╔════════════════════════════════════════════════╗\n");
- printf(" ║ MIDInterface 1.11 16 Track Digital Recorder ║\n");
- printf(" ╚════════════════════════════════════════════════╝\n");
- printf("\n");
- printf(" Main Menu:\n");
- printf(" ──────────\n");
- printf(" 1..........Erase a track\n");
- printf(" 2..........Record to a track\n");
- printf(" 3..........Play from a track\n");
- printf(" 4..........Track information\n");
- printf(" 5..........Save a track\n");
- printf(" 6..........Load a track\n");
- printf(" 7..........Set MIDI modes\n");
- printf(" 8..........Edit input filter\n");
- printf(" 0..........Quit\n");
- scr_rowcol(24,0);
- printf(" Copyright (C) 1985, 1986 by Jay Kubicky");
- scr_rowcol(18,0);
- printf(" Enter Selection:");
- sel=getchar();
- switch (sel) {
- case '1':
- erbuff();
- break;
- case '2':
- recbuff();
- break;
- case '3':
- pbuffs();
- break;
- case '4':
- dbuffs();
- break;
- case '5':
- strack();
- break;
- case '6':
- ltrack();
- break;
- case '7':
- mmode();
- break;
- case '8':
- ed_in_filt();
- break;
- case '0':
- scr_cla();
- b=0;
- for(a=0; a<16; ++a) {
- if(parts[a].ssize) {
- b=1; /* toggle high */
- printf(" Data still left in track %d\n",a);
- }
- }
- if(!b) {
- close(pfd);
- exit(0);
- }
- printf("Still want to exit? ");
- if(toupper(getchar()) == 'Y') {
- close(pfd);
- exit(0);
- }
- default:
- goto start;
- }
- goto start;
- }
-
- /* DBUFFS
- This is the general buffer display routine.
- It displays all pertinent data for all avaiable buffers.
- */
- dbuffs()
- {
- char a,b; unsigned tn,nf,nu;
- s_: scr_cla();
- printf(" Track Assignment Screen:\n");
- printf(" ════════════════════════\n");
- printf("Track Num: Transmit Chan: Notes Used: Transpose: Enabeled:\n");
- printf("%s\n",sin_line);
- for(a=0; a<16; ++a) {
- if(segment[a]) {
- tn=(endp[a]-startp[a])/8;
- nf=tn-(parts[a].ssize/8);
- nu=tn-nf;
- b=parts[a].transpose;
- printf("%d\t\t%d\t\t%d\t\t%d\t\t%s\n",a,parts[a].chan,nu,b < 128 ? b : -256+b, buffon[a] || (a==rbuff) ? yes : no);
- }
- else
- printf("--\t\t--\t\t--\t\t--\t\t--\n");
- }
- printf("%s\n",sin_line);
- ttag: scr_rowcol(21,0);
- printf("Chng one trans. channel (1), change all (2), transpose (3), enable status (4)\n");
- printf("or (0) to quit/continue: ");
- a=getchar();
- scr_rowcol(22,17);
- scr_cls(); /* clear rest of current line */
- switch(a) {
- case '0':
- return;
- break;
- case '1':
- printf(" Enter track number:");
- b=getint();
- scr_rowcol(23,0);
- printf(" Enter new transmit channel:");
- parts[b].chan=getint();
- break;
- case '2':
- printf(" Enter new transmit channel for all tracks:");
- a=getint();
- for(b=0; b<16; ++b)
- parts[b].chan=a;
- break;
- case '3':
- printf(" Enter track number:");
- b=getint();
- scr_rowcol(23,0);
- printf(" Enter new transpose amount:");
- parts[b].transpose=getint();
- break;
- case '4':
- printf(" Enter track number:");
- b=getint();
- if(parts[b].ssize && b != rbuff)
- buffon[b]= buffon[b] ? 0 : 1;
- break;
- default:
- goto ttag;
- }
- goto s_;
- }
-
- /* ERBUFF
- This funct. erase a buffer (set the size to 0)
- */
- erbuff()
- {
- scr_cla();
- char b;
- printf(" Erase a Track\n");
- printf("%s\n",sin_line);
- printf("\nWhich buffer? ");
- b=getint();
- printf("Are you sure you want to erase buffer %d?",b);
- if(toupper(getchar()) != 'Y')
- return;
- parts[b].ssize=0;
- buffon[b]=0;
- }
-
- /* PBUFFS
- This is the top-level play-buffer routine.
- */
- pbuffs()
- {
- int m;
- copyptrs();
-
- scr_cla();
- printf(" Play Track Mode\n");
- printf("%s\n\n\n",sin_line);
- printf(" Hit any key to continue\n");
- getchar();
- dbuffs();
-
- scr_cla();
- printf(" Play Track Mode\n");
- printf("%s\n\n\n",sin_line);
-
- get_options();
-
- printf("\nHit space bar to continue, any other key to quit\n");
- if(getchar()!=32)
- return;
- setrec();
- destbyte=0xff;
- play();
- intoff();
- _outb(5,MIDIS); /* send off to drum mach. */
- _outb(104,MIDIS);
- _outb(0xfc,MIDID); /* MIDI seq off */
- for(m=0; m<16; ++m) {
- if(parts[m].ssize)
- buffon[m]=1;
- }
- }
-
- /*
- RECBUFF:
- This is the track record routine.
- All it really does is set up & enable the interrupt routine -
- RxInt
- */
- recbuff()
- {
- char b; int m;
- copyptrs();
- scr_cla();
- printf(" Record a Track\n");
- printf("%s\n\n",sin_line);
- printf(" Which buffer:");
- b=getint();
- if(parts[b].ssize) {
- printf("That buffer already has music, still want to record (Y/N)?");
- if(toupper(getchar()) != 'Y')
- return;
- }
- if(!segment[b]) {
- printf("Sorry, that track is not available to record in.\n");
- hak();
- return;
- }
- rbuff=b;
- parts[b].ssize=0;
- dbuffs(); /* display buff enable board w/ option to change */
- scr_cla();
-
- get_options();
-
- printf("\nHit any key to begin recording\n");
- getchar();
- scr_cla();
- printf("Hit any key to stop recording\n");
-
- setrec();
- play();
-
- _poke(255,ptr,segment[rbuff]); /* EOS (end-of-song) */
- parts[b].ssize=ptr-startp[rbuff];
- printf("\nSong is %d notes long\n",parts[b].ssize / 8);
- rbuff=255; /* no more record buffer */
- pointers[b]=startp[b]; /* copy start pointer */
- buffon[b]=1; /* enable present buffer */
-
- _outb(5,MIDIS); /* send off to drum mach. */
- _outb(104,MIDIS);
- _outb(0xfc,MIDID); /* MIDI seq off */
-
- rbuff=0xff;
- hak();
- }
-
- /* SETREC
- This sets up almost everything for Play & Record.
- */
- setrec()
- {
- int a;
-
- stop=0;
- destbyte=0;
- setint();
- ptr=startp[rbuff];
- end=endp[rbuff];
- r_segment=segment[rbuff];
- end=endp[rbuff];
- C_O_F=0x90;
- beat=abeat=mbeat=0xfe;
- if(dsync) {
- _outb(5,MIDIS); /* send start to drums */
- _outb(104+128,MIDIS);
- }
- if(MIDIsync)
- _outb(0xfa,MIDID); /* start ext seq */
- pointers[0]=startp[0];
- pointers[1]=startp[1];
- setcounter(tempo & 0xff,tempo >> 8,255,255);
- }
-
- copyptrs() /* copy start pstns of buffers into pointer areas */
- {
- char a;
- for(a=0; a<15; ++a)
- pointers[a]=startp[a];
- }
-
- /* LTRACK
- Load a track into memory.
- */
- ltrack()
- {
- char tr;
- scr_cla();
- printf(" Load a Track\n");
- printf("%s\n",sin_line);
- dir("????????","???");
- scr_rowcol(2,0);
- printf(" Load which track:");
- tr=getint();
- if(parts[tr].ssize) {
- printf("Data already in that track ... aborting.\n");
- getchar(); return; }
- printf(" Load from which file:");
- scanf("%s",filename);
- if((fd=open(filename,2)) == -1) {
- printf("Can't open %s ... aborting\n",filename);
- getchar();
- return;
- }
- if(read(fd,parts[tr],63) == -1) {
- printf("Error encountered during reading.\n");
- getchar();
- return;
- }
- if(seg_read(fd,tr,parts[tr].ssize+1) == -1) {
- printf("Error encountered while reading.\n");
- getchar(); return; }
- close(fd);
- printf("Total bytes loaded from disk:%d\n",parts[tr].ssize+63);
- buffon[tr]=1;
- getchar();
- }
-
- /* STRACK
- Save a track to disk.
- */
- strack() /* save a track */
- {
- char tr;
- scr_cla();
- printf(" Save a Track\n");
- printf("%s\n",sin_line);
- dir("????????","???");
- scr_rowcol(2,0);
- printf(" Save which track:");
- tr=getint();
- if(!parts[tr].ssize) {
- printf("Nothing in that track ... aborting.\n");
- getchar(); return; }
- printf(" Save to what file:");
- scanf("%s",filename);
- if((fd=creat(filename)) == -1) {
- printf("Can't creat %s ... aborting\n",filename);
- getchar();
- return;
- }
- if(write(fd,parts[tr],63) == -1) {
- printf("Error encountered during writing.\n");
- getchar();
- goto _end;
- }
- if(seg_write(fd,tr,parts[tr].ssize+1) == -1) {
- printf("Error encountered while writing.\n");
- getchar(); goto _end; }
- close(fd);
- printf("Total bytes written to disk:%d\n",parts[tr].ssize+63);
- hak();
- return;
- _end:
- close(fd);
- }
-
- /* SEG_READ, SEG_WRITE
- These functions carry out intra-segmentary disk I/O functions.
- */
- seg_read(fd,tr,size)
- int fd, tr; unsigned size;
- {
- unsigned a;
- a=startp[tr]; /* this won't be 0 for tr. 0 & 1 : it's a pointer */
-
- if(size > 1024) {
- size+=a; /* make size look like a pointer */
- for(;a < (size-1024); a+=1024) {
- if(read(fd,vir_buff,1024) == -1)
- return(-1);
- _lmove(1024,vir_buff,_showds(),a,segment[tr]);
- }
- }
- else
- size+=a;
-
- if(!(size-a))
- return(1);
- if(read(fd,vir_buff,size-a) == -1)
- return(-1);
- _lmove(size-a,vir_buff,_showds(),a,segment[tr]);
- return(1);
- }
-
- seg_write(fd,tr,size)
- int fd, tr; unsigned size;
- {
- unsigned a;
- a=startp[tr]; /* this won't always be 0 because of tracks 0 & 1 */
-
- if(size > 1024) {
- size+=a; /* make size look like a pointer */
- for(;a < (size-1024); a+=1024) {
- _lmove(1024,a,segment[tr],vir_buff,_showds());
- if(write(fd,vir_buff,1024) == -1)
- return(-1);
- }
- }
- else
- size+=a;
-
- if(!(size-a)) /* Is the buff length 0 || have we written all data? */
- return(1);
- _lmove(size-a,a,segment[tr],vir_buff,_showds());
- if(write(fd,vir_buff,size-a) == -1)
- return(-1);
- return(1);
- }
-
- /* play() -
- This function plays through the 16 tracks until track 0 ends
- or a key is struck.
- */
- play()
- {
- int playing;
- char a,ch,b;
- unsigned n;
- scr_rowcol(2,0);
- printf("Tempo: %d",r_tempo);
- sp:
- for (a=0; a<15; ++a) {
- if(buffon[a] && a!=rbuff) {
- if(playfrom(a)) { /* Track or song end */
- if(a) /* if not track 0 */
- buffon[a]=0; /* turn off buff */
- else
- return;
- }
- }
- if(dsync)
- bt();
- if(MIDIsync)
- bt2();
- if(audmet)
- bt3();
- }
- if(!(ch=scr_csts()))
- goto sp;
- else {
- switch(ch) {
- case '+':
- ++r_tempo;
- break;
- case '-':
- --r_tempo;
- break;
- default:
- return;
- }
- scr_rowcol(2,10);
- printf("%d",r_tempo);
- tempo=2000000/((r_tempo*48)/60);
- set_cnt_1(tempo,tempo >> 8);
- }
- goto sp;
- }
- playfrom(a)
- char a;
- {
- char *p,d,*p1;
- p=vir_buff;
- _lmove(8,pointers[a],segment[a],vir_buff,_showds());
-
- if(*p==0xff) /* check for EOS */
- return(1);
-
- readclk();
- p1=p+2;
- if(*p1 > cmsb)
- goto pnow;
- if(*p1 < cmsb)
- return(0);
- if(*(p+1) < clsb)
- return(0);
- pnow: /* now we know that it's time to play [notes]... */
- d=*p & 0xc0;
- switch(d) {
- case 00: /* note on or off */
- pnt(p,parts[a].chan,parts[a].transpose);
- pointers[a]+=4;
- break;
- case 0x40: /* prog chan / chan pres. / key pres. */
- pchan(p,parts[a].chan);
- pointers[a]+=4;
- break;
- case 0x80: /* pitch bender */
- w_f_e(); /* let FIFO empty */
- _outb(0xE0+parts[a].chan,MIDID); /* send P. B. code */
- w_f_e(); /* let FIFO empty */
- _outb(0,MIDID); /* we didn't store LSB */
- w_f_e();
- _outb(*p << 1,MIDID); /* send MSB */
- pointers[a]+=3;
- break;
- case 0xC0: /* cntrl chan | temp chan */
- cchan(p,parts[a].chan);
- if(!(*p&1)); /* make up for control change */
- ++pointers[a];
- pointers[a]+=4;
- break;
- }
- return(0);
- }
-
- pnt(p,tc,trans)
- char *p,tc,trans;
- {
- # asm
- MOV SI,WORD [BP+4] ; get p
- MOV AL,BYTE [SI+3] ; get *(p+3)
- AND AL,128 ; strip off top bit
- JZ znoff ; play a note off
- MOV AL,BYTE [BP+6] ; get tchan
- ADD AL,090H ; add a basic note on
- zcheat1: ; here's where we'll cheat on a Note OFF
- MOV DX,0FFA0H ; MIDI Data port
- CALL w_f_e_ ; wait for DART FIFO to empty
- OUT DX,AL ; send byte
- MOV AL,BYTE [SI+3] ; get note to turn on
- ADD AL,BYTE [BP+8] ; add transpose val.
- AND AL,07FH ; strip off top bit
- CALL w_f_e_ ; wait for DART FIFO to empty
- OUT DX,AL ; send out note
- MOV AL,BYTE [SI] ; get velocity
- SHL AL,1 ; shift up into range
- CALL w_f_e_ ; wait for DART FIFO to empty out
- OUT DX,AL ; send velocity
- JMP zalldone ; finished
-
- znoff: ; send Note OFF command
- MOV AL,BYTE [BP+6] ; get transmit channel
- ADD AL,080H ; add basic Note OFF
- JMP zcheat1 ; let's take a short cut
-
- zalldone: ; all done
-
- #
- }
-
- pchan(p,tc) /* Program change, channel pressure, or after-touch */
- char *p,tc;
- {
- # asm
- MOV DX,0FFA0H ; DART port
- MOV SI,WORD [BP+4] ; get p
- MOV AL,BYTE [SI] ; get I.D. byte
- CMP AL,040H ; I.D. for Prog change
- JZ zpchan ; branch if Prog change
- CMP AL,041H ; I.D. for Chan pressure, after-touch
- JZ zchanp
- ; else, Poly. key press. (after-touch)
- MOV AL,BYTE [BP+6] ; get transmit chan
- ADD AL,0A0H ; poly. key pressure
- CALL w_f_e_
- OUT DX,AL ; send 1st byte
- MOV AL,BYTE [SI+3] ; get key #
- CALL w_f_e_
- OUT DX,AL
- MOV AL,BYTE [SI] ; get pressure
- AND AL,01FH ; strip off bottom 5
- SHL AL,1
- SHL AL,1 ; bumb up two bits
- CALL w_f_e_
- OUT DX,AL
- JMP zalldone2 ; all done
-
- zpchan: ; program change
- MOV AL,BYTE [BP+6] ; get transmit channel
- ADD AL,0C0H ; basic prog chan
- JMP zcheat2 ; use code from above routine
- zchanp: ; channel pressure
- MOV AL,BYTE [BP+6] ; get transmit channel
- ADD AL,0D0H ; add basic chan pres
- JMP zcheat2
- zcheat2: ; entry point from zpchan
- CALL w_f_e_ ; wait for DART
- OUT DX,AL ; send byte
- MOV AL,BYTE [SI+3] ; get new vel
- OUT DX,AL ; send
-
- zalldone2: ; FINE
- #
- }
-
- cchan(p,tc)
- char *p,tc;
- {
- # asm
- MOV SI,WORD [BP+4] ; get p
- MOV AL,BYTE [SI] ; get I.D. byte
- AND AL,1 ; bit 0
- JNZ ztchan ; tempo change
- ; now we know it's a cntrl chan
- MOV AL,0B0H ; cntrl chan
- ADD AL,BYTE [BP+6] ; add transmit channel
- MOV DX,0FFA0H ; MIDID port
- CALL w_f_e_ ; wait for DART to empty
- OUT DX,AL
- MOV AL,BYTE [SI+3] ; get cntrl #
- CALL w_f_e_ ; wait for DART FIFO to empty
- OUT DX,AL
- MOV AL,BYTE [SI+4] ; get cntrl val
- CALL w_f_e_
- OUT DX,AL
- JMP _fine2 ; done
-
- ztchan: ; tempo change
- ; MOV AL,extsync_
- ; OR AL,AL ; set flags
- ; JNZ _fine2 ; if extsync mode, then this has no purpose
- #
- /* tempo(*(p+3)+30); */
- # asm
-
- _fine2:
-
- #
- }
-
- w_f_e() /* this function "sleeps" until the FIFO in the DART is empty */
- {
- # asm
- PUSH DX
- PUSH AX
- MOV DX,0FFA2H ; DART status register
- try_again:
- IN AL,DX
- AND AL,4 ; Tx buff empty?
- JZ try_again ; no?
- POP AX
- POP DX
- #
- }
- /*
- BT, BT2, BT3
- These are the meternome counting routines.
- */
- bt()
- {
- readclk();
- if(beat==clsb) {
- _outb(5,MIDIS+1); /* send sync high */
- _outb(128,MIDIS+1);
- _outb(5,MIDIS+1); /* send sync low */
- _outb(0,MIDIS+1);
- beat-=s_t_b;
- }
- }
-
- bt2()
- {
- readclk();
- if(mbeat==clsb) {
- _outb(0xf8,MIDID); /* MIDI timing clk */
- mbeat-=m_t_b;
- }
- }
-
- bt3()
- {
- readclk();
- if(abeat==clsb) {
- if(printer)
- beepp();
- abeat-=a_t_b;
- }
- }
- beepp()
- {
- _rax=0x0500;
- _rdx=7;
- _doint(0x21);
- }
- /* SETINT
- This routine sets up the interrupt.
- */
- setint()
- {
-
-
- int rxint(),a;
- int seg_num, (*fun_add)();
-
- fun_add = rxint;
- seg_num=_showcs();
- _poke(fun_add & 0xff,0x28,0); _poke(fun_add >> 8,0x29,0);
- _poke(seg_num & 0xff,0x2a,0); _poke(seg_num >> 8,0x2b,0);
- setdart();
- setpic();
- }
-
- setdart()
- {
- _outb(24,MIDIS); /* reset channel A */
- _outb(1,MIDIS); _outb(24,MIDIS); /* int on all Rx + Ext Stat */
- _outb(3,MIDIS); _outb(193,MIDIS);
- _outb(4,MIDIS); _outb(196,MIDIS);
- _outb(5,MIDIS); _outb(104,MIDIS);
- }
- setpic()
- {
- char a;
- a=_inb(PIC1); /* read interrupt mask */
- if(a&4) /* if DART is masked off */
- a-=4;
- _outb(a,PIC1); /* re-enable ints */
- }
-
- setcounter(l1,m1,l2,m2)
- char l1,m1,l2,m2;
- {
- char e,d;
- _outb(0x34,CSTAT); /* counter 1=mode 2 - read/load both */
- e=d; d=e;
- _outb(0x70,CSTAT); /* counter 2= mode 0 - read/load both */
- e=d; d=e;
- _outb(l2,COUNTER2); /* set LSB of counter 2 */
- e=d; d=e;
- _outb(m2,COUNTER2); /* set MSB of counter 2 */
- e=d; d=e;
- _outb(l1,COUNTER1); /* set LSB of counter 1 */
- e=d; d=e;
- _outb(m1,COUNTER1); /* set MSB of counter 1 */
- readclk();
- while(cmsb!=255 && clsb!=255)
- readclk();
- return;
- }
- set_cnt_1(l1,m1)
- char l1,m1;
- {
- _outb(l1,COUNTER1); /* set LSB of counter 1 */
- _outb(m1,COUNTER1); /* set MSB of counter 1 */
- }
-
- intoff()
- {
- _outb(01,MIDIS); /* turn off my interrupt */
- _outb(00,MIDIS); /* (at the DART) */
- }
- inton()
- {
- _outb(01,MIDIS); /* turn on my interrupt */
- _outb(24,MIDIS); /* (at the DART) */
- }
- readclk()
- {
- # asm
- MOV AL,64
- MOV DX,0FFA7H
- CLI ; an interrupt right now from Rxint would be bad
- OUT DX,AL
- NOP
- NOP
- NOP
- SUB DX,2
- IN AL,DX
- MOV clsb_,AL
- NOP
- NOP
- NOP
- IN AL,DX
- MOV cmsb_,AL
- STI ; ints back on
- #
- }
-
- scr_cla() /* clear screen & pstn cursor at top */
- {
- scr_clr();
- scr_rowcol(0,0);
- }
-
- /* MMODE
- This is a no-frills routine for setting up various
- MIDI system modes
- */
- mmode()
- {
- char a,mo,v;
- st:
- scr_cla();
- printf(" MIDI mode assignments:\n");
- printf("%s\n",sin_line);
- ss:
- putchar('\n');
- printf(" 1 - Omni ON / Poly\n");
- printf(" 2 - Omni OFF / Poly\n");
- printf(" 3 - Omni ON / Mono\n");
- printf(" 4 - Omni OFF / Mono\n");
- printf(" 5 - Program change\n");
- printf(" 6 - All notes off (all channels)\n");
- printf(" 7 - All notes off (one channel)\n");
- printf(" 0 - Exit\n");
- printf("Enter new mode:");
- mo=getint();
- if(!mo)
- return;
- if(mo>7)
- goto st;
- if(mo==6)
- goto skip;
- printf("Send over which channel:");
- a=getint(); if(a > 15)
- goto ss;
- printf("\nChannel %d:\n",a);
- skip:
- switch(mo) {
- case 1:
- printf(" Poly / Omni on\n");
- poly(a);
- o_on(a);
- break;
- case 2:
- printf(" Poly / Omni off\n");
- poly(a);
- omni_off(a);
- break;
- case 3:
- printf(" Mono / Omni on\n");
- mono(a);
- o_on(a);
- break;
- case 4:
- printf(" Mono / Omni off\n");
- mono(a);
- omni_off(a);
- break;
- case 5:
- printf(" Program change\n");
- printf(" Enter new program: ");
- v=getint();
- _outb(192+a,MIDID);
- _outb(v,MIDID);
- break;
- case 6:
- for(a=0; a<16; ++a) {
- _outb(0xb0+a,MIDID);
- _outb(123,MIDID);
- w_f_e();
- _outb(0,MIDID);
- }
- printf(" All notes off - all channels\n");
- getchar();
- break;
- case 7:
- _outb(0xb0+a,MIDID);
- _outb(123,MIDID);
- w_f_e();
- _outb(0,MIDID);
- printf(" All notes off\n");
- getchar();
- break;
- }
- goto st;
- }
-
- o_on(ch)
- char ch;
- {
- _outb(176+ch,MIDID);
- _outb(125,MIDID);
- w_f_e();
- _outb(0,MIDID);
- getchar();
- }
-
- omni_off(ch)
- char ch;
- {
- _outb(176+ch,MIDID);
- _outb(124,MIDID);
- w_f_e();
- _outb(0,MIDID);
- getchar();
- }
-
- poly(ch)
- char ch;
- {
- _outb(176+ch,MIDID);
- _outb(127,MIDID);
- w_f_e();
- _outb(0,MIDID);
- getchar();
- }
-
- mono(ch)
- char ch;
- {
- char v;
- printf("How many channels? (0 = # in receiver, or other) ");
- v=getint();
- _outb(176+ch,MIDID);
- _outb(126,MIDID);
- w_f_e();
- _outb(v,MIDID);
- getchar();
- }
-
- get_av_mem() /* returns total system RAM - in K */
- {
- _doint(0x012);
- return(_rax);
- }
-
- char *_showss()
- {
- # asm
- MOV AX,SS
- #
- }
-
- hak() /* display "hit any key to continue" & wait */
- {
- puts("\n\n");
- scr_cls();
- puts(" Hit any key to continue.");
- while(!scr_csts());
- }
-
- getint() /* error check an input line & return int */
- {
- char inln[20],*b,flag;
- stg:
- _gets(inln,20);
- if(strlen(inln)) {
- for(b=inln;*b!='\0';++b) {
- if(!isdigit(*b) && *b != '-') {
- putchar(7);
- goto stg;
- }
- }
- return(atoi(inln));
- }
- else
- putchar(7);
- goto stg;
- }
-
- /* ED_IN_FILT
- This routine allows the user to edit the input filter
- */
- ed_in_filt()
- {
- int n;
- scr_cla();
- scr_rowcol(0,26);
- printf("Edit Input Filter\n");
- printf("%s\n\n",sin_line);
- st_filt:
- scr_rowcol(3,0);
- printf(" Mess #: Message type: Status:\n");
- printf(" ──────────┬────────────────────────┬───────────\n");
- printf(" 1 │ Note ON │ %s\n",(in_filt & 1) ? yes : no);
- printf(" 2 │ Note OFF │ %s\n",(in_filt & 2) ? yes : no);
- printf(" 3 │ Program Change │ %s\n",(in_filt & 4) ? yes : no);
- printf(" 4 │ Channel Pressure │ %s\n",(in_filt & 8) ? yes : no);
- printf(" 5 │ Pitch Wheel │ %s\n",(in_filt & 16) ? yes : no);
- printf(" 6 │ Control Change │ %s\n",(in_filt & 32) ? yes : no);
- printf(" 7 │ Poly. Key Pressure │ %s\n",(in_filt & 64) ? yes : no);
- printf(" ──────────┴────────────────────────┴───────────\n");
- printf("\n\n\n\n\n");
- re_try:
- scr_rowcol(18,12);
- printf("Enter Message Number to toggle, 0 to end: ");
- n=getint();
- if(n<0 || n>7)
- goto re_try;
- if(!n)
- return;
- n=1 << (n-1); /* make n into bit to complement */
- in_filt = in_filt & n ? in_filt-n : in_filt+n;
- goto st_filt;
-
- }
-
- get_options() /* enter various user options */
- {
-
- em: printf("Enter metrenome speed:");
- r_tempo=getint();
- if(r_tempo<40 || r_tempo>200)
- goto em;
- tempo=2000000/((r_tempo*48)/60);
- printf("Audio Sync (Y/N):");
- audmet=(toupper(getchar())=='Y') ? 1:0;
- putchar('\n');
- printf("Drum Sync (Y/N):");
- dsync=(toupper(getchar())=='Y') ? 1:0;
- putchar('\n');
- printf("MIDI Sync (Y/N):");
- MIDIsync=(toupper(getchar())=='Y') ? 1:0;
- }
-
- /* dir(fname,ext)
- char *fname,*ext;
-
- This function shows a directory of the currently logged directory
- and disk and print it on the screen in "five-across" format.
- */
-
- dir(fname,ext) /* function to show directory of currently logged disk & dir */
- char *fname,*ext; /* pointers to filename & extension */
- {
-
- struct fcb {
- char drive_num;
- char filename[8];
- char extension[3];
- char rest[25]; /* the rest of the fcb */
- } fcb;
-
- struct fcb fcb2;
- unsigned dta_add, dta_seg;
- char filename[21];
- char flag=4;
- char cnt=80;
-
- fcb.drive_num=0;
- strcpy(filename," ");
- strncpy(fcb.filename,fname,8);
- strncpy(fcb.extension,ext,3);
- _setmem(fcb.rest,25,0);
-
- _rax=0x2f00; /* get current DTA */
- _doint(0x21);
- dta_add=_rbx;
- dta_seg=_res; /* this is the offset & segment of the current DTA */
-
- _rdx=fcb;
- _rds=_showds();
- _rax=0x1100;
-
- scr_rowcol(6,0);
- printf("%s\n",sin_line);
- scr_rowcol(7,0);
- scr_cls();
- for(;;) {
- _doint(0x21);
- if((_rax & 0xff))
- break; /* last file has been listed */
- _lmove(20,dta_add,dta_seg,fcb2,_showds());
- strncpy(filename,fcb2.filename,8);
- filename[8]='.';
- filename[9]='\0';
- strcat(filename,fcb2.extension);
- filename[12]='\0';
- puts(filename);
- puts(" ");
- if(!flag)
- flag=5;
- if(!--cnt) {
- printf(" Hit any key to continue.");
- getchar();
- scr_rowcol(7,0);
- scr_cls();
- cnt=80;
- flag=4;
- }
- --flag;
- _rax=0x1200;
- }
- }